home *** CD-ROM | disk | FTP | other *** search
/ Precision Software Appli…tions Silver Collection 1 / Precision Software Applications Silver Collection Volume One (PSM) (1993).iso / windows / games / wincapt.arj / FILE.C < prev    next >
C/C++ Source or Header  |  1992-07-31  |  15KB  |  494 lines

  1. //*******************************************************************
  2. //
  3. //  file.c
  4. //
  5. //  Source file for Device-Independent Bitmap (DIB) API.  Provides
  6. //  the following functions:
  7. //
  8. //  SaveDIB()           - Saves the specified dib in a file
  9. //  LoadDIB()           - Loads a DIB from a file
  10. //  DestroyDIB()        - Deletes DIB when finished using it
  11. //
  12. // Development Team: Mark Bader
  13. //                   Patrick Schreiber
  14. //                   Garrett McAuliffe
  15. //                   Eric Flo
  16. //                   Tony Claflin
  17. //
  18. // Written by Microsoft Product Support Services, Developer Support.
  19. // Copyright (c) 1991 Microsoft Corporation. All rights reserved.
  20. //*******************************************************************
  21.  
  22. #include <windows.h>
  23. #include <string.h>
  24. #include <stdio.h>
  25. #include <math.h>
  26. #include <io.h>
  27. #include <direct.h>
  28. #include <stdlib.h>
  29. #include "dibutil.h"
  30. #include "dibapi.h"
  31.  
  32. /*
  33.  * Dib Header Marker - used in writing DIBs to files
  34.  */
  35. #define DIB_HEADER_MARKER   ((WORD) ('M' << 8) | 'B')
  36.  
  37.  
  38. /*********************************************************************
  39.  *
  40.  * Local Function Prototypes
  41.  *
  42.  *********************************************************************/
  43.  
  44.  
  45. HANDLE ReadDIBFile(int);
  46. BOOL MyRead(int, LPSTR, DWORD);
  47. BOOL SaveDIBFile(void);
  48. BOOL WriteDIB(LPSTR, HANDLE);
  49. DWORD PASCAL MyWrite(int, VOID FAR *, DWORD);
  50.  
  51. /*************************************************************************
  52.  *
  53.  * LoadDIB()
  54.  *
  55.  * Loads the specified DIB from a file, allocates memory for it,
  56.  * and reads the disk file into the memory.
  57.  *
  58.  *
  59.  * Parameters:
  60.  *
  61.  * LPSTR lpFileName - specifies the file to load a DIB from
  62.  *
  63.  * Returns: A handle to a DIB, or NULL if unsuccessful.
  64.  *
  65.  * NOTE: The DIB API were not written to handle OS/2 DIBs; This
  66.  * function will reject any file that is not a Windows DIB.
  67.  *
  68.  * History:   Date      Author       Reason
  69.  *            9/15/91   Mark Bader   Based on DIBVIEW
  70.  *
  71.  *************************************************************************/
  72.  
  73.  
  74. HDIB FAR LoadDIB(LPSTR lpFileName)
  75. {
  76.    HDIB hDIB;
  77.    int hFile;
  78.    OFSTRUCT ofs;
  79.  
  80.    /*
  81.     * Set the cursor to a hourglass, in case the loading operation
  82.     * takes more than a sec, the user will know what's going on.
  83.     */
  84.  
  85.    SetCursor(LoadCursor(NULL, IDC_WAIT));
  86.    if ((hFile = OpenFile(lpFileName, &ofs, OF_READ)) != -1)
  87.    {
  88.       hDIB = ReadDIBFile(hFile);
  89.       _lclose(hFile);
  90.       SetCursor(LoadCursor(NULL, IDC_ARROW));
  91.       return hDIB;
  92.    }
  93.    else
  94.    {
  95.       DIBError(ERR_FILENOTFOUND);
  96.       SetCursor(LoadCursor(NULL, IDC_ARROW));
  97.       return NULL;
  98.    }
  99. }
  100.  
  101.  
  102. /*************************************************************************
  103.  *
  104.  * SaveDIB()
  105.  *
  106.  * Saves the specified DIB into the specified file name on disk.  No
  107.  * error checking is done, so if the file already exists, it will be
  108.  * written over.
  109.  *
  110.  * Parameters:
  111.  *
  112.  * HDIB hDib - Handle to the dib to save
  113.  *
  114.  * LPSTR lpFileName - pointer to full pathname to save DIB under
  115.  *
  116.  * Return value: 0 if successful, or one of:
  117.  *        ERR_INVALIDHANDLE
  118.  *        ERR_OPEN
  119.  *        ERR_LOCK
  120.  *
  121.  * History:
  122.  *
  123.  * NOTE: The DIB API were not written to handle OS/2 DIBs, so this
  124.  * function will not save a file if it is not a Windows DIB.
  125.  *
  126.  * History:   Date      Author       Reason
  127.  *            9/15/91   Mark Bader   Taken from DIBVIEW (which was taken
  128.  *                                      from SHOWDIB)
  129.  *            1/30/92   Mark Bader   Fixed problem of writing too many 
  130.  *                                      bytes to the file
  131.  *            6/24/92   Mark Bader   Added check for OS/2 DIB
  132.  *
  133.  *************************************************************************/
  134.  
  135.  
  136. WORD FAR SaveDIB(HDIB hDib, LPSTR lpFileName)
  137. {
  138.    BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
  139.    LPBITMAPINFOHEADER lpBI;   // Pointer to DIB info structure
  140.    int fh;     // file handle for opened file
  141.    OFSTRUCT of;     // OpenFile structure
  142.    DWORD dwDIBSize;
  143.    DWORD dwError;   // Error return from MyWrite
  144.  
  145.    if (!hDib)
  146.       return ERR_INVALIDHANDLE;
  147.    fh = OpenFile(lpFileName, &of, OF_CREATE | OF_READWRITE);
  148.    if (fh == -1)
  149.       return ERR_OPEN;
  150.  
  151.    /*
  152.     * Get a pointer to the DIB memory, the first of which contains
  153.     * a BITMAPINFO structure
  154.     */
  155.    lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib);
  156.    if (!lpBI)
  157.       return ERR_LOCK;
  158.  
  159.    // Check to see if we're dealing with an OS/2 DIB.  If so, don't
  160.    // save it because our functions aren't written to deal with these
  161.    // DIBs.
  162.  
  163.    if (lpBI->biSize != sizeof(BITMAPINFOHEADER))
  164.    {
  165.      GlobalUnlock(hDib);
  166.      return ERR_NOT_DIB;
  167.    }
  168.  
  169.    /*
  170.     * Fill in the fields of the file header
  171.     */
  172.  
  173.    /* Fill in file type (first 2 bytes must be "BM" for a bitmap) */
  174.    bmfHdr.bfType = DIB_HEADER_MARKER;  // "BM"
  175.  
  176.    // Calculating the size of the DIB is a bit tricky (if we want to
  177.    // do it right).  The easiest way to do this is to call GlobalSize()
  178.    // on our global handle, but since the size of our global memory may have
  179.    // been padded a few bytes, we may end up writing out a few too
  180.    // many bytes to the file (which may cause problems with some apps,
  181.    // like HC 3.0).
  182.    //
  183.    // So, instead let's calculate the size manually.
  184.    //
  185.    // To do this, find size of header plus size of color table.  Since the
  186.    // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
  187.    // the size of the structure, let's use this.
  188.  
  189.    dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI);  // Partial Calculation
  190.  
  191.    // Now calculate the size of the image
  192.  
  193.    if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4)) {
  194.  
  195.       // It's an RLE bitmap, we can't calculate size, so trust the
  196.       // biSizeImage field
  197.  
  198.       dwDIBSize += lpBI->biSizeImage;
  199.       }
  200.    else {
  201.       DWORD dwBmBitsSize;  // Size of Bitmap Bits only
  202.  
  203.       // It's not RLE, so size is Width (DWORD aligned) * Height
  204.  
  205.       dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
  206.  
  207.       dwDIBSize += dwBmBitsSize;
  208.       
  209.       // Now, since we have calculated the correct size, why don't we
  210.       // fill in the biSizeImage field (this will fix any .BMP files which 
  211.       // have this field incorrect).
  212.  
  213.       lpBI->biSizeImage = dwBmBitsSize;
  214.       }
  215.  
  216.  
  217.    // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
  218.                    
  219.    bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
  220.    bmfHdr.bfReserved1 = 0;
  221.    bmfHdr.bfReserved2 = 0;
  222.  
  223.    /*
  224.     * Now, calculate the offset the actual bitmap bits will be in
  225.     * the file -- It's the Bitmap file header plus the DIB header,
  226.     * plus the size of the color table.
  227.     */
  228.    bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +
  229.                       PaletteSize((LPSTR)lpBI);
  230.  
  231.    /* Write the file header */
  232.    _lwrite(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
  233.  
  234.    /*
  235.     * Write the DIB header and the bits -- use local version of
  236.     * MyWrite, so we can write more than 32767 bytes of data
  237.     */
  238.    dwError = MyWrite(fh, (LPSTR)lpBI, dwDIBSize);
  239.    GlobalUnlock(hDib);
  240.    _lclose(fh);
  241.  
  242.    if (dwError == 0)
  243.      return ERR_OPEN; // oops, something happened in the write
  244.    else
  245.      return 0; // Success code
  246. }
  247.  
  248.  
  249. /*************************************************************************
  250.  *
  251.  * DestroyDIB ()
  252.  *
  253.  * Purpose:  Frees memory associated with a DIB
  254.  *
  255.  * Returns:  Nothing
  256.  *
  257.  * History:   Date      Author       Reason
  258.  *            9/15/91   Mark Bader   Created
  259.  *
  260.  *************************************************************************/
  261.  
  262.  
  263. WORD FAR DestroyDIB(HDIB hDib)
  264. {
  265.    GlobalFree(hDib);
  266.    return 0;
  267. }
  268.  
  269.  
  270. //************************************************************************
  271. //
  272. // Auxiliary Functions which the above procedures use
  273. //
  274. //************************************************************************
  275.  
  276.  
  277. /*************************************************************************
  278.  *
  279.  * Function:  ReadDIBFile (int)
  280.  *
  281.  *  Purpose:  Reads in the specified DIB file into a global chunk of
  282.  *            memory.
  283.  *
  284.  *  Returns:  A handle to a dib (hDIB) if successful.
  285.  *            NULL if an error occurs.
  286.  *
  287.  * Comments:  BITMAPFILEHEADER is stripped off of the DIB.  Everything
  288.  *            from the end of the BITMAPFILEHEADER structure on is
  289.  *            returned in the global memory handle.
  290.  *
  291.  *
  292.  * NOTE: The DIB API were not written to handle OS/2 DIBs, so this
  293.  * function will reject any file that is not a Windows DIB.
  294.  *
  295.  * History:   Date      Author       Reason
  296.  *            9/15/91   Mark Bader   Based on DIBVIEW
  297.  *            6/25/92   Mark Bader   Added check for OS/2 DIB
  298.  *            7/21/92   Mark Bader   Added code to deal with bfOffBits
  299.  *                                     field in BITMAPFILEHEADER
  300.  *
  301.  *************************************************************************/
  302.  
  303. HANDLE ReadDIBFile(int hFile)
  304. {
  305.    BITMAPFILEHEADER bmfHeader;
  306.    DWORD dwBitsSize;
  307.    UINT nNumColors;   // Number of colors in table
  308.    HANDLE hDIB;
  309.    LPBITMAPINFOHEADER lpbi;
  310.    DWORD offBits;
  311.  
  312.    /*
  313.     * get length of DIB in bytes for use when reading
  314.     */
  315.  
  316.    dwBitsSize = filelength(hFile);
  317.  
  318.    // Allocate memory for header & color table.    We'll enlarge this
  319.    // memory as needed.
  320.  
  321.    hDIB = GlobalAlloc(GMEM_MOVEABLE,
  322.        (DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
  323.    
  324.    if (!hDIB) return NULL;
  325.  
  326.    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  327.    if (!lpbi) 
  328.    {
  329.      GlobalFree(hDIB);
  330.      return NULL;
  331.    }
  332.  
  333.    // read the BITMAPFILEHEADER from our file
  334.  
  335.    if (sizeof (BITMAPFILEHEADER) != _lread (hFile, (LPSTR)&bmfHeader, sizeof (BITMAPFILEHEADER)))
  336.      goto ErrExit;
  337.  
  338.    if (bmfHeader.bfType != 0x4d42)    /* 'BM' */
  339.      goto ErrExit;
  340.  
  341.    // read the BITMAPINFOHEADER
  342.  
  343.    if (sizeof(BITMAPINFOHEADER) != _lread (hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
  344.      goto ErrExit;
  345.  
  346.    // Check to see that it's a Windows DIB -- an OS/2 DIB would cause
  347.    // strange problems with the rest of the DIB API since the fields
  348.    // in the header are different and the color table entries are
  349.    // smaller.
  350.    //
  351.    // If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
  352.  
  353.    if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
  354.      goto ErrExit;
  355.  
  356.    // Now determine the size of the color table and read it.  Since the
  357.    // bitmap bits are offset in the file by bfOffBits, we need to do some
  358.    // special processing here to make sure the bits directly follow
  359.    // the color table (because that's the format we are susposed to pass
  360.    // back)
  361.  
  362.    if (!(nNumColors = (UINT)lpbi->biClrUsed))
  363.     {
  364.       // no color table for 24-bit, default size otherwise
  365.       if (lpbi->biBitCount != 24)
  366.         nNumColors = 1 << lpbi->biBitCount; /* standard size table */
  367.     }
  368.  
  369.    // fill in some default values if they are zero
  370.    if (lpbi->biClrUsed == 0)
  371.      lpbi->biClrUsed = nNumColors;
  372.  
  373.    if (lpbi->biSizeImage == 0)
  374.    {
  375.      lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
  376.              * lpbi->biHeight;
  377.    }
  378.  
  379.    // get a proper-sized buffer for header, color table and bits
  380.    GlobalUnlock(hDIB);
  381.    hDIB = GlobalReAlloc(hDIB, lpbi->biSize +
  382.                         nNumColors * sizeof(RGBQUAD) +
  383.                         lpbi->biSizeImage, 0);
  384.  
  385.    if (!hDIB) // can't resize buffer for loading
  386.      return NULL;
  387.  
  388.    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  389.  
  390.    // read the color table
  391.    _lread (hFile, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
  392.  
  393.    // offset to the bits from start of DIB header
  394.    offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
  395.  
  396.    // If the bfOffBits field is non-zero, then the bits might *not* be
  397.    // directly following the color table in the file.  Use the value in
  398.    // bfOffBits to seek the bits.
  399.  
  400.    if (bmfHeader.bfOffBits != 0L)
  401.       _llseek(hFile, bmfHeader.bfOffBits, SEEK_SET);
  402.    
  403.    if (MyRead(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
  404.      goto OKExit;
  405.  
  406.  
  407. ErrExit:
  408.     GlobalUnlock(hDIB);
  409.     GlobalFree(hDIB);
  410.     return NULL;
  411.  
  412. OKExit:
  413.     GlobalUnlock(hDIB);
  414.     return hDIB;
  415. }
  416.  
  417. /*************************************************************************
  418.  
  419.   Function:  MyRead (int, LPSTR, DWORD)
  420.  
  421.    Purpose:  Routine to read files greater than 64K in size.
  422.  
  423.    Returns:  TRUE if successful.
  424.              FALSE if an error occurs.
  425.  
  426.   
  427.   History:   Date      Author       Reason
  428.              9/15/91   Mark Bader   Based on DIBVIEW
  429.  
  430. *************************************************************************/
  431.  
  432.  
  433. BOOL MyRead(int hFile, LPSTR lpBuffer, DWORD dwSize)
  434. {
  435.    char huge *lpInBuf = (char huge *)lpBuffer;
  436.    int nBytes;
  437.  
  438.    /*
  439.     * Read in the data in 32767 byte chunks (or a smaller amount if it's
  440.     * the last chunk of data read)
  441.     */
  442.  
  443.    while (dwSize)
  444.    {
  445.       nBytes = (int)(dwSize > (DWORD)32767 ? 32767 : LOWORD (dwSize));
  446.       if (_lread(hFile, (LPSTR)lpInBuf, nBytes) != (WORD)nBytes)
  447.          return FALSE;
  448.       dwSize -= nBytes;
  449.       lpInBuf += nBytes;
  450.    }
  451.    return TRUE;
  452. }
  453.  
  454.  
  455. /****************************************************************************
  456.  
  457.  FUNCTION   : MyWrite(int fh, VOID FAR *pv, DWORD ul)
  458.  
  459.  PURPOSE    : Writes data in steps of 32k till all the data is written.
  460.               Normal _lwrite uses a WORD as 3rd parameter, so it is
  461.               limited to 32767 bytes, but this procedure is not.
  462.  
  463.  RETURNS    : 0 - If write did not proceed correctly.
  464.               number of bytes written otherwise.
  465.  
  466.   History:   Date      Author       Reason
  467.              9/15/91   Mark Bader   Based on DIBVIEW
  468.  
  469.  ****************************************************************************/
  470.  
  471.  
  472. DWORD PASCAL MyWrite(int iFileHandle, VOID FAR *lpBuffer, DWORD dwBytes)
  473. {
  474.    DWORD dwBytesTmp = dwBytes;       // Save # of bytes for return value
  475.    BYTE huge *hpBuffer = lpBuffer;   // make a huge pointer to the data
  476.  
  477.    /*
  478.     * Write out the data in 32767 byte chunks.
  479.     */
  480.  
  481.    while (dwBytes > 32767)
  482.    {
  483.       if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)32767) != 32767)
  484.          return 0;
  485.       dwBytes -= 32767;
  486.       hpBuffer += 32767;
  487.    }
  488.  
  489.    /* Write out the last chunk (which is < 32767 bytes) */
  490.    if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)dwBytes) != (WORD)dwBytes)
  491.       return 0;
  492.    return dwBytesTmp;
  493. }
  494.